home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DJGPP
/
CBGRX103.ZIP
/
contrib
/
libgrx
/
src
/
mouse.c
< prev
next >
Wrap
Text File
|
1993-12-06
|
16KB
|
658 lines
/**
** MOUSE.C
**
** Copyright (C) 1992, Csaba Biegl
** 820 Stirrup Dr, Nashville, TN, 37221
** csaba@vuse.vanderbilt.edu
**
** This file is distributed under the terms listed in the document
** "copying.cb", available from the author at the address above.
** A copy of "copying.cb" should accompany this file; if not, a copy
** should be available from where this file was obtained. This file
** may not be distributed without a verbatim copy of "copying.cb".
** You should also have received a copy of the GNU General Public
** License along with this program (it is in the file "copying");
** if not, write to the Free Software Foundation, Inc., 675 Mass Ave,
** Cambridge, MA 02139, USA.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**/
#include "grx.h"
#include "mousex.h"
#include "libgrx.h"
#include "interrup.h"
#include "clipping.h"
#include "../events/eventque.h"
#include <string.h>
#include <stdarg.h>
#ifdef __TURBOC__
# include <time.h>
# include <conio.h>
#endif
#ifdef __GNUC__
extern long rawclock();
# define clock() rawclock()
#endif
/*
* mouse status flags
*/
#define UNKNOWN 0
#define MISSING 1
#define PRESENT 2
#define INITTED 3
#define QUEUED 4
#define DRAW_STACK 1024
#define QUEUE_SIZE 100
#define CHECK_CONTEXT(cxt) ((cxt)->gc_baseaddr == SCREEN->gc_baseaddr)
extern GrCursor *_GrMouseCursor; /* current mouse cursor */
static EventQueue *queue,qbuf;
static int mouse_status = UNKNOWN;
static int own_cursor = FALSE;
static int use_queue = FALSE;
static int kb_enable = TRUE;
static int ms_enable = TRUE;
static int ms_curmode = M_CUR_NORMAL;
static int ms_xanchor,ms_yanchor;
static int ms_dx2,ms_dy2;
static int ms_curcolor;
static int ms_buttons;
static int ms_xpos;
static int ms_ypos;
#define ms_dx1 ms_xanchor
#define ms_dy1 ms_yanchor
static void (*getevent)(int flags,MouseEvent *event);
static char ptr12x16bits[] = {
0,1,0,0,0,0,0,0,0,0,0,0,
1,2,1,0,0,0,0,0,0,0,0,0,
1,2,2,1,0,0,0,0,0,0,0,0,
1,2,2,2,1,0,0,0,0,0,0,0,
1,2,2,2,2,1,0,0,0,0,0,0,
1,2,2,2,2,2,1,0,0,0,0,0,
1,2,2,2,2,2,2,1,0,0,0,0,
1,2,2,2,2,2,2,2,1,0,0,0,
1,2,2,2,2,2,2,2,2,1,0,0,
1,2,2,2,2,2,2,2,2,2,1,0,
1,2,2,2,2,2,2,2,2,2,2,1,
1,2,2,2,2,1,1,1,1,1,1,0,
1,2,2,2,1,0,0,0,0,0,0,0,
1,2,2,1,0,0,0,0,0,0,0,0,
1,2,1,0,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,0,0,0,0,0,0,
};
static int check_mouse(void)
{
if(mouse_status < INITTED) {
if(mouse_status != MISSING) MouseInit();
if(mouse_status < INITTED) return(FALSE);
}
return(TRUE);
}
static void draw_special(void)
{
int x = _GrMouseCursor->cr_xcord;
int y = _GrMouseCursor->cr_ycord;
int msflag = _GrMouseCheck;
GrContext csave;
csave = *CURC;
*CURC = *SCREEN;
_GrMouseCheck = FALSE;
switch(ms_curmode) {
case M_CUR_RUBBER:
GrBox(x,y,ms_xanchor,ms_yanchor,ms_curcolor);
break;
case M_CUR_LINE:
GrLine(x,y,ms_xanchor,ms_yanchor,ms_curcolor);
break;
case M_CUR_BOX:
GrBox(x+ms_dx1,y+ms_dy1,x+ms_dx2,y+ms_dy2,ms_curcolor);
break;
}
*CURC = csave;
_GrMouseCheck = msflag;
}
static void draw_mouse(void)
{
if(_GrMouseCursor->cr_displayed) return;
GrMoveCursor(_GrMouseCursor,queue->evq_xpos,queue->evq_ypos);
GrDisplayCursor(_GrMouseCursor);
if(ms_curmode != M_CUR_NORMAL) draw_special();
}
static void erase_mouse(void)
{
if(!_GrMouseCursor->cr_displayed) return;
if(ms_curmode != M_CUR_NORMAL) draw_special();
GrEraseCursor(_GrMouseCursor);
}
static void move_mouse(void)
{
#ifdef CRASH_AT_0_0
if((queue->evq_xpos == 0) && (queue->evq_ypos == 0)) {
char tmp[20];
char *ptr = (char *)NULL;
int crashval = ++(*ptr);
sprintf(tmp,"%d",crashval);
}
#endif
if(!_GrMouseCursor->cr_displayed) {
GrMoveCursor(_GrMouseCursor,queue->evq_xpos,queue->evq_ypos);
return;
}
if(ms_curmode != M_CUR_NORMAL) draw_special();
GrMoveCursor(_GrMouseCursor,queue->evq_xpos,queue->evq_ypos);
if(ms_curmode != M_CUR_NORMAL) draw_special();
}
static void get_polled_event(int flags,MouseEvent *e)
{
REGISTERS regs;
int moved;
int diff;
for( ; ; ) {
if((flags & M_KEYPRESS) && kbhit()) {
e->flags = M_KEYPRESS;
e->x = queue->evq_xpos;
e->y = queue->evq_ypos;
e->key = getxkey();
e->kbstat = getkbstat();
e->time = clock();
return;
}
moved = 0;
regs.r_ax = 11;
int33(®s);
if((diff = (short)regs.r_cx) != 0) {
ms_xpos += diff;
if((diff = ms_xpos / queue->evq_xspeed) != 0) {
ms_xpos %= queue->evq_xspeed;
if(IABS(diff) >= queue->evq_thresh) diff *= queue->evq_accel;
diff += queue->evq_xpos;
if(diff <= queue->evq_xmin) diff = queue->evq_xmin;
if(diff >= queue->evq_xmax) diff = queue->evq_xmax;
if(diff != queue->evq_xpos) {
queue->evq_xpos = diff;
queue->evq_moved = 1;
moved = M_MOTION;
}
}
}
if((diff = (short)regs.r_dx) != 0) {
ms_ypos += diff;
if((diff = ms_ypos / queue->evq_yspeed) != 0) {
ms_ypos %= queue->evq_yspeed;
if(IABS(diff) >= queue->evq_thresh) diff *= queue->evq_accel;
diff += queue->evq_ypos;
if(diff <= queue->evq_ymin) diff = queue->evq_ymin;
if(diff >= queue->evq_ymax) diff = queue->evq_ymax;
if(diff != queue->evq_ypos) {
queue->evq_ypos = diff;
queue->evq_moved = 1;
moved = M_MOTION;
}
}
}
if(moved && queue->evq_drawmouse) move_mouse();
regs.r_ax = 3;
int33(®s);
if(flags & M_BUTTON_DOWN) {
diff = (regs.r_bx & ~ms_buttons);
if(diff & M_LEFT) moved |= M_LEFT_DOWN;
if(diff & M_MIDDLE) moved |= M_MIDDLE_DOWN;
if(diff & M_RIGHT) moved |= M_RIGHT_DOWN;
}
if(flags & M_BUTTON_UP) {
diff = (~regs.r_bx & ms_buttons);
if(diff & M_LEFT) moved |= M_LEFT_UP;
if(diff & M_MIDDLE) moved |= M_MIDDLE_UP;
if(diff & M_RIGHT) moved |= M_RIGHT_UP;
}
ms_buttons = regs.r_bx & (M_LEFT | M_MIDDLE | M_RIGHT);
if(flags & (moved | M_POLL)) {
e->flags = moved & flags;
e->x = queue->evq_xpos;
e->y = queue->evq_ypos;
e->buttons = ms_buttons;
e->kbstat = getkbstat();
e->time = clock();
return;
}
}
}
static void get_queued_event(int flags,MouseEvent *e)
{
EventRecord evr;
int moved = 0;
for( ; ; ) {
if(queue->evq_moved) {
moved = M_MOTION;
queue->evq_moved = 0;
}
if(EventQueueNextEvent(queue,&evr)) {
switch(evr.evt_type) {
case EVENT_KEYBD:
if(flags & M_KEYPRESS) {
e->flags = M_KEYPRESS;
e->x = queue->evq_xpos;
e->y = queue->evq_ypos;
e->key = evr.evt_keycode;
e->kbstat = evr.evt_kbstat;
e->time = evr.evt_time;
return;
}
break;
case EVENT_MOUSE:
ms_buttons = evr.evt_button;
if(flags & evr.evt_mask) {
e->flags = flags & (evr.evt_mask | moved);
e->x = evr.evt_xpos;
e->y = evr.evt_ypos;
e->buttons = evr.evt_button;
e->kbstat = evr.evt_kbstat;
e->time = evr.evt_time;
return;
}
break;
}
continue;
}
if(flags & (moved | M_POLL)) {
e->flags = flags & moved;
e->x = queue->evq_xpos;
e->y = queue->evq_ypos;
e->buttons = ms_buttons;
e->kbstat = getkbstat();
e->time = clock();
return;
}
}
}
void MouseEventMode(int use_interrupts)
{
use_queue = use_interrupts;
}
int MouseDetect(void)
{
REGISTERS regs;
if(mouse_status == UNKNOWN) {
regs.r_ax = 0;
int33(®s);
mouse_status = (regs.r_ax == 0) ? MISSING : PRESENT;
}
return((mouse_status == MISSING) ? FALSE : TRUE);
}
void MouseUnInit(void)
{
REGISTERS regs;
if(mouse_status >= INITTED) {
if(mouse_status == QUEUED) {
EventQueueDeInit();
queue = NULL;
}
else {
regs.r_ax = 0;
int33(®s);
}
if(_GrMouseDrawn) erase_mouse();
mouse_status = PRESENT;
}
}
void MouseInit(void)
{
REGISTERS regs;
if(mouse_status != PRESENT) {
MouseDetect();
MouseUnInit();
if(mouse_status != PRESENT) return;
}
if(use_queue) {
queue = EventQueueInit(QUEUE_SIZE,DRAW_STACK,move_mouse);
if(queue != NULL) {
mouse_status = QUEUED;
getevent = get_queued_event;
queue->evq_drawmouse = FALSE;
}
}
if(mouse_status < INITTED) {
queue = &qbuf;
regs.r_ax = 0;
int33(®s);
regs.r_ax = 3;
int33(®s);
ms_buttons = regs.r_bx & (M_LEFT | M_MIDDLE | M_RIGHT);
regs.r_ax = 11;
int33(®s);
ms_xpos = 0;
ms_ypos = 0;
getevent = get_polled_event;
mouse_status = INITTED;
}
if(_GrMouseCursor == NULL) MouseSetColors(GrWhite(),GrBlack());
_GrMouseBlock = MouseBlock;
_GrMouseUnBlock = MouseUnBlock;
_GrMouseUnInit = MouseUnInit;
_GrMouseDrawn = FALSE;
_GrMouseCheck = FALSE;
MouseEventEnable(kb_enable,ms_enable);
MouseSetLimits(0,0,(_GrScreenX - 1),(_GrScreenY - 1));
MouseWarp((_GrScreenX >> 1),(_GrScreenY >> 1));
MouseSetSpeed(1);
MouseSetAccel(1000,1);
}
void MouseSetSpeed(int speed)
{
if(!check_mouse()) return;
queue->evq_xspeed = speed;
queue->evq_yspeed = speed;
}
void MouseSetAccel(int thresh,int accel)
{
if(!check_mouse()) return;
queue->evq_thresh = thresh;
queue->evq_accel = accel;
}
void MouseSetLimits(int x1,int y1,int x2,int y2)
{
if(!check_mouse()) return;
CLIPBOXTOCONTEXT(SCREEN,x1,y1,x2,y2);
queue->evq_xmin = x1;
queue->evq_ymin = y1;
queue->evq_xmax = x2;
queue->evq_ymax = y2;
MouseWarp(queue->evq_xpos,queue->evq_ypos);
}
void MouseGetLimits(int *x1,int *y1,int *x2,int *y2)
{
if(!check_mouse()) return;
*x1 = queue->evq_xmin;
*y1 = queue->evq_ymin;
*x2 = queue->evq_xmax;
*y2 = queue->evq_ymax;
}
void MouseWarp(int x,int y)
{
char msdraw;
if(!check_mouse()) return;
msdraw = queue->evq_drawmouse;
queue->evq_drawmouse = FALSE;
if(x < queue->evq_xmin) x = queue->evq_xmin;
if(y < queue->evq_ymin) y = queue->evq_ymin;
if(x > queue->evq_xmax) x = queue->evq_xmax;
if(y > queue->evq_ymax) y = queue->evq_ymax;
queue->evq_xpos = x;
queue->evq_ypos = y;
if(_GrMouseDrawn) move_mouse();
queue->evq_drawmouse = msdraw;
}
void MouseSetCursor(GrCursor *cursor)
{
GrCursor *old = _GrMouseCursor;
char msdraw = 0;
if(cursor != NULL) {
if(mouse_status >= INITTED) {
msdraw = queue->evq_drawmouse;
queue->evq_drawmouse = FALSE;
if(_GrMouseDrawn) erase_mouse();
}
_GrMouseCursor = cursor;
if(own_cursor) GrDestroyCursor(old);
own_cursor = FALSE;
if(mouse_status >= INITTED) {
if(_GrMouseDrawn) draw_mouse();
queue->evq_drawmouse = msdraw;
}
}
}
void MouseSetColors(int fg,int bg)
{
GrCursor *new;
int cols[3];
cols[0] = 2;
cols[1] = bg;
cols[2] = fg;
new = GrBuildCursor(ptr12x16bits,12,16,1,1,cols);
if(new != NULL) {
MouseSetCursor(new);
own_cursor = TRUE;
}
}
void MouseSetCursorMode(int mode,...)
{
va_list ap;
char msdraw = 0;
if(mouse_status >= INITTED) {
msdraw = queue->evq_drawmouse;
queue->evq_drawmouse = FALSE;
if(_GrMouseDrawn && (ms_curmode != M_CUR_NORMAL)) draw_special();
}
va_start(ap,mode);
switch(mode) {
case M_CUR_RUBBER:
ms_curmode = M_CUR_RUBBER;
ms_xanchor = va_arg(ap,int);
ms_yanchor = va_arg(ap,int);
ms_curcolor = (va_arg(ap,int) & C_COLOR) | GrXOR;
break;
case M_CUR_LINE:
ms_curmode = M_CUR_LINE;
ms_xanchor = va_arg(ap,int);
ms_yanchor = va_arg(ap,int);
ms_curcolor = (va_arg(ap,int) & C_COLOR) | GrXOR;
break;
case M_CUR_BOX:
ms_curmode = M_CUR_BOX;
ms_dx1 = va_arg(ap,int);
ms_dy1 = va_arg(ap,int);
ms_dx2 = va_arg(ap,int);
ms_dy2 = va_arg(ap,int);
ms_curcolor = (va_arg(ap,int) & C_COLOR) | GrXOR;
break;
default:
ms_curmode = M_CUR_NORMAL;
break;
}
va_end(ap);
if(mouse_status >= INITTED) {
if(_GrMouseDrawn && (ms_curmode != M_CUR_NORMAL)) draw_special();
queue->evq_drawmouse = msdraw;
}
}
GrCursor *MouseGetCursor(void)
{
return(_GrMouseCursor);
}
int MouseCursorIsDisplayed(void)
{
return(_GrMouseDrawn);
}
void MouseDisplayCursor(void)
{
if((mouse_status < INITTED) || _GrMouseDrawn) return;
draw_mouse();
_GrMouseDrawn = TRUE;
_GrMouseCheck = CHECK_CONTEXT(CURC) ? TRUE : FALSE;
queue->evq_drawmouse = TRUE;
}
void MouseEraseCursor(void)
{
if((mouse_status < INITTED) || !_GrMouseDrawn) return;
queue->evq_drawmouse = FALSE;
_GrMouseDrawn = FALSE;
_GrMouseCheck = FALSE;
erase_mouse();
}
#define BLK_MOTION 1 /* "MouseBlock" froze the mouse */
#define BLK_DISPLAY 2 /* "MouseBlock" erased the mouse */
#define BLK_CHECK 4 /* "MouseBlock" cleared check flag */
int MouseBlock(GrContext *c,int x1,int y1,int x2,int y2)
{
int mx1,my1,mx2,my2;
int retval;
if(mouse_status < INITTED) return(0);
if(!_GrMouseDrawn) return(0);
if(c == NULL) c = CURC;
if(!CHECK_CONTEXT(c)) return(0);
retval = queue->evq_drawmouse ? BLK_MOTION : 0;
queue->evq_drawmouse = FALSE;
queue->evq_moved = FALSE;
SORT2(x1,x2);
SORT2(y1,y2);
x1 += c->gc_xoffset; y1 += c->gc_yoffset;
x2 += c->gc_xoffset; y2 += c->gc_yoffset;
mx1 = _GrMouseCursor->cr_xwpos;
my1 = _GrMouseCursor->cr_ywpos;
mx2 = mx1 + _GrMouseCursor->cr_xwork - 1;
my2 = my1 + _GrMouseCursor->cr_ywork - 1;
if(ms_curmode != M_CUR_NORMAL) {
int cx2,cy2;
int cx1 = _GrMouseCursor->cr_xcord;
int cy1 = _GrMouseCursor->cr_ycord;
switch(ms_curmode) {
case M_CUR_RUBBER:
case M_CUR_LINE:
cx2 = ms_xanchor;
cy2 = ms_yanchor;
break;
case M_CUR_BOX:
cx2 = cx1 + ms_dx2;
cy2 = cy1 + ms_dy2;
cx1 += ms_dx1;
cy2 += ms_dy1;
break;
default:
return(retval);
}
SORT2(cx1,cx2);
SORT2(cy1,cy2);
if(cx1 < mx1) mx1 = cx1;
if(cy1 < my1) my1 = cy1;
if(cx2 > mx2) mx2 = cx2;
if(cy2 > my2) my2 = cy2;
}
if(mx1 > x1) x1 = mx1;
if(my1 > y1) y1 = my1;
if(mx2 < x2) x2 = mx2;
if(my2 < y2) y2 = my2;
if((x1 <= x2) && (y1 <= y2)) {
_GrMouseDrawn = FALSE;
retval |= BLK_DISPLAY;
erase_mouse();
}
if(_GrMouseCheck) {
_GrMouseCheck = FALSE;
retval |= BLK_CHECK;
}
return(retval);
}
void MouseUnBlock(int flags)
{
if(mouse_status < INITTED) return;
if(queue->evq_moved && (flags & BLK_MOTION)) move_mouse();
if(!_GrMouseDrawn && (flags & BLK_DISPLAY)) {
draw_mouse();
_GrMouseDrawn = TRUE;
}
_GrMouseCheck = ((CHECK_CONTEXT(CURC) && (flags & BLK_CHECK)) ?
TRUE :
FALSE
);
if(flags & BLK_MOTION) queue->evq_drawmouse = TRUE;
}
void MouseEventEnable(int enable_kb,int enable_ms)
{
if(mouse_status >= INITTED) {
queue->evq_enable =
(enable_kb ? EVENT_ENABLE(EVENT_KEYBD) : 0) |
(enable_ms ? EVENT_ENABLE(EVENT_MOUSE) : 0);
}
kb_enable = enable_kb;
ms_enable = enable_ms;
}
void MouseGetEvent(int flags,MouseEvent *e)
{
int erase = FALSE;
if(!kb_enable) flags &= ~M_KEYPRESS;
if(!ms_enable) flags &= ~(M_MOTION | M_BUTTON_DOWN | M_BUTTON_UP);
if(!(flags & M_EVENT)) { e->flags = 0; return; }
if(!check_mouse()) {
e->flags = 0;
if((flags & M_KEYPRESS) && (!(flags & M_POLL) || kbhit())) {
e->flags = M_KEYPRESS;
e->key = getkey();
e->kbstat = getkbstat();
e->time = clock();
}
return;
}
if(!_GrMouseDrawn && !(flags & M_NOPAINT)) {
draw_mouse();
queue->evq_drawmouse = TRUE;
erase = TRUE;
}
(*getevent)(flags,e);
if(erase) {
queue->evq_drawmouse = FALSE;
erase_mouse();
}
}
int MousePendingEvent(void)
{
if((mouse_status >= INITTED) && (queue->evq_cursize > 0))
return(TRUE);
return(FALSE);
}